﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;

namespace LuckyBingoRcon.Matches
{
    /// <summary>
    /// Known Gametypes:
    /// 1;Team Deathmatch (18)
    /// 2;Free For All (18)
    /// 3;Capture The Flag (18)
    /// 4;Search & Destroy (18)
    /// 5;Headquarters (18)
    /// 6;Domination (18)
    /// 7;Sabotage (18)
    /// 8;Demolition (18)
    /// 9;Hardcore Team Deathmatch (18)
    /// 10;Hardcore Free For All (18)
    /// 11;Hardcore Capture The Flag (18)
    /// 12;Hardcore Search & Destroy (18)
    /// 13;Hardcore Headquarters (18)
    /// 14;Hardcore Domination (18)
    /// 15;Hardcore Sabotage (18)
    /// 16;Hardcore Demolition (18)
    /// 17;Barebones Team Deathmatch (18)
    /// 18;Barebones Free For All (18)
    /// 19;Barebones Capture The Flag (18)
    /// 20;Barebones Search & Destroy (18)
    /// 21;Barebones Headquarters (18)
    /// 22;Barebones Domination (18)
    /// 23;Barebones Sabotage (18)
    /// 24;Barebones Demolition (18)
    /// 25;Team Tactical (18)
    /// 26;One in the Chamber (6)
    /// 27;Sticks and Stones (6)
    /// 28;Gun Game (6)
    /// 29;Sharpshooter (6)
    /// 30;Hardcore Team Tactical (18)
    /// 31;Barebones Team Tactical (18)
    /// 32;Team Deathmatch (12)
    /// 33;Free For All (12)
    /// 34;Capture The Flag (12)
    /// 35;Search & Destroy (12)
    /// 36;Headquarters (12)
    /// 37;Domination (12)
    /// 38;Sabotage (12)
    /// 39;Demolition (12)
    /// 40;Team Tactical (12)
    /// 41;Hardcore Team Deathmatch (12)
    /// 42;Hardcore Free For All (12)
    /// 43;Hardcore Capture The Flag (12)
    /// 44;Hardcore Search & Destroy (12)
    /// 45;Hardcore Headquarters (12)
    /// 46;Hardcore Domination (12)
    /// 47;Hardcore Sabotage (12)
    /// 48;Hardcore Demolition (12)
    /// 49;Hardcore Team Tactical (12)
    /// 50;Barebones Team Deathmatch (12)
    /// 51;Barebones Free For All (12)
    /// 52;Barebones Capture The Flag (12)
    /// 53;Barebones Search & Destroy (12)
    /// 54;Barebones Headquarters (12)
    /// 55;Barebones Domination (12)
    /// 56;Barebones Sabotage (12)
    /// 57;Barebones Team Tactical (12)
    /// </summary>
    public class GametypeLookup
    {
        private Dictionary<int, string> num2Name = new Dictionary<int, string>();                           // Contains playlist number key, gametype value
        private Dictionary<string, int> name2Num = new Dictionary<string, int>();                           // Contains gametype key, playlist number value
        private Dictionary<string, List<int>> gametypeCollection = new Dictionary<string, List<int>>();     // Contains base gametype and all associated playlists with that base gametype
        private Dictionary<string, List<int>> baseGametypes = new Dictionary<string, List<int>>();          // Contains base gametype abbreviations

        public GametypeLookup()
        {
            FileInfo gametypeFile = new FileInfo("Configs\\gametypeList.cfg");
            if (gametypeFile.Exists)                  // Found the Map List Config file, load from there
            {
                string[] configStrings = File.ReadAllLines(gametypeFile.FullName);
                string[] args;
                int playListNum;
                foreach (string entry in configStrings)
                {
                    if (entry.StartsWith("//"))
                        continue;
                    args = Regex.Split(entry, ";");
                    try
                    {
                        playListNum = Convert.ToInt16(args[0]);
                    }
                    catch
                    {
                        continue;
                    }
                    num2Name.Add(playListNum, args[1]);
                }
            }
            else                                // Can't find Gametype List Config file, use Gametype defaults (Gametypes as of 15 December 2010)
            {
                //RconForm.Console.WriteLine("Could not find file: <Root>\\Configs\\gametypeList.cfg");
                num2Name.Add(1, "Team Deathmatch (18)");
                num2Name.Add(2, "Free For All (18)");
                num2Name.Add(3, "Capture The Flag (18)");
                num2Name.Add(4, "Search & Destroy (18)");
                num2Name.Add(5, "Headquarters (18)");
                num2Name.Add(6, "Domination (18)");
                num2Name.Add(7, "Sabotage (18)");
                num2Name.Add(8, "Demolition (18)");
                num2Name.Add(9, "Hardcore Team Deathmatch (18)");
                num2Name.Add(10, "Hardcore Free For All (18)");
                num2Name.Add(11, "Hardcore Capture The Flag (18)");
                num2Name.Add(12, "Hardcore Search & Destroy (18)");
                num2Name.Add(13, "Hardcore Headquarters (18)");
                num2Name.Add(14, "Hardcore Domination (18)");
                num2Name.Add(15, "Hardcore Sabotage (18)");
                num2Name.Add(16, "Hardcore Demolition (18)");
                num2Name.Add(17, "Barebones Team Deathmatch (18)");
                num2Name.Add(18, "Barebones Free For All (18)");
                num2Name.Add(19, "Barebones Capture The Flag (18)");
                num2Name.Add(20, "Barebones Search & Destroy (18)");
                num2Name.Add(21, "Barebones Headquarters (18)");
                num2Name.Add(22, "Barebones Domination (18)");
                num2Name.Add(23, "Barebones Sabotage (18)");
                num2Name.Add(24, "Barebones Demolition (18)");
                num2Name.Add(25, "Team Tactical (18)");
                num2Name.Add(26, "One in the Chamber (6)");
                num2Name.Add(27, "Sticks and Stones (6)");
                num2Name.Add(28, "Gun Game (6)");
                num2Name.Add(29, "Sharpshooter (6)");
                num2Name.Add(30, "Hardcore Team Tactical (18)");
                num2Name.Add(31, "Barebones Team Tactical (18)");
                num2Name.Add(32, "Team Deathmatch (12)");
                num2Name.Add(33, "Free For All (12)");
                num2Name.Add(34, "Capture The Flag (12)");
                num2Name.Add(35, "Search & Destroy (12)");
                num2Name.Add(36, "Headquarters (12)");
                num2Name.Add(37, "Domination (12)");
                num2Name.Add(38, "Sabotage (12)");
                num2Name.Add(39, "Demolition (12)");
                num2Name.Add(40, "Team Tactical (12)");
                num2Name.Add(41, "Hardcore Team Deathmatch (12)");
                num2Name.Add(42, "Hardcore Free For All (12)");
                num2Name.Add(43, "Hardcore Capture The Flag (12)");
                num2Name.Add(44, "Hardcore Search & Destroy (12)");
                num2Name.Add(45, "Hardcore Headquarters (12)");
                num2Name.Add(46, "Hardcore Domination (12)");
                num2Name.Add(47, "Hardcore Sabotage (12)");
                num2Name.Add(48, "Hardcore Demolition (12)");
                num2Name.Add(49, "Hardcore Team Tactical (12)");
                num2Name.Add(50, "Barebones Team Deathmatch (12)");
                num2Name.Add(51, "Barebones Free For All (12)");
                num2Name.Add(52, "Barebones Capture The Flag (12)");
                num2Name.Add(53, "Barebones Search & Destroy (12)");
                num2Name.Add(54, "Barebones Headquarters (12)");
                num2Name.Add(55, "Barebones Domination (12)");
                num2Name.Add(56, "Barebones Sabotage (12)");
                num2Name.Add(57, "Barebones Team Tactical (12)");               
            }
            
            string gametypeName = string.Empty;
            int spaceLoc = -1;
            int paraLoc = -1;
            List<int> gametypeNums = new List<int>();
            gametypeCollection.Add("Any", new List<int>() { 0 });
            foreach (int key in num2Name.Keys)
            {
                name2Num.Add(num2Name[key], key);
                if (num2Name[key].Contains("Barebones") || num2Name[key].Contains("Hardcore"))
                {
                    spaceLoc = num2Name[key].IndexOf(" ");
                    paraLoc = num2Name[key].IndexOf("(");
                    int length = paraLoc - (spaceLoc + 1) - 1;
                    if (!spaceLoc.Equals(-1) && !paraLoc.Equals(-1) && length > 0)
                        gametypeName = num2Name[key].Substring(spaceLoc + 1, length);
                }
                else
                {
                    paraLoc = num2Name[key].IndexOf("(");
                    if (!paraLoc.Equals(-1))
                        gametypeName = num2Name[key].Substring(0, paraLoc - 1);
                }
                if (gametypeCollection.ContainsKey(gametypeName) == false)
                    gametypeCollection.Add(gametypeName, new List<int>() { key });
                else
                {
                    gametypeNums = gametypeCollection[gametypeName];
                    gametypeNums.Add(key);
                    gametypeCollection[gametypeName] = gametypeNums;
                }
            }
            foreach (List<int> val in gametypeCollection.Values)
            {
                switch (val[0])
                {
                    case 1:
                        baseGametypes.Add("tdm", val);
                        break;
                    case 2:
                        baseGametypes.Add("dm", val);
                        break;
                    case 3:
                        baseGametypes.Add("ctf", val);
                        break;
                    case 4:
                        baseGametypes.Add("sd", val);
                        break;
                    case 5:
                        baseGametypes.Add("koth", val);
                        break;
                    case 6:
                        baseGametypes.Add("dom", val);
                        break;
                    case 7:
                        baseGametypes.Add("sab", val);
                        break;
                    case 8:
                        baseGametypes.Add("dem", val);
                        break;
                }
            }
        }

        /// <summary>
        /// NOT IMPLEMENTED, haven't decided on a file format
        /// </summary>
        /// <param name="playListNum"></param>
        public GametypeLookup(int playListNum)
        {
            // not implemented
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="playListName"></param>
        /// <returns>NULL if playListNum is not known</returns>
        public int GetPlayListNumber(string playListName)
        {
            if (name2Num.ContainsKey(playListName))
            {
                return name2Num[playListName];
            }
            else
            {
                return -1;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="playListNum"></param>
        /// <returns>NULL if playListName is not known</returns>
        public string GetPlayListName(int playListNum)
        {
            if (num2Name.ContainsKey(playListNum))
            {
                return num2Name[playListNum];
            }
            else
            {
                return null;
            }
        }

        public bool IsValidPlayList(string playList)
        {
            if (playList.Equals("Any"))
                return true;
            try
            {
                short num = Convert.ToInt16(playList);
                return num2Name.ContainsKey(num);
            }
            catch
            {
                return name2Num.ContainsKey(playList);
            }
        }

        public int[] GetPlayListNumbers()
        {
            int[] ia = new int[num2Name.Keys.Count];
            num2Name.Keys.CopyTo(ia, 0);
            return ia;
        }

        public string[] GetPlayListNames()
        {
            string[] sa = new string[name2Num.Keys.Count];
            name2Num.Keys.CopyTo(sa, 0);
            return sa;
        }

        public string[] GetUniquePlayListNames()
        {
            string[] sa = new string[gametypeCollection.Keys.Count];
            gametypeCollection.Keys.CopyTo(sa, 0);
            return sa;
        }

        public List<int> GetAllowablePlaylists(string key)
        {
            string gametypeName = string.Empty;
            if (key.Contains("Barebones") || key.Contains("Hardcore"))
            {
                int spaceLoc = key.IndexOf(" ");
                int paraLoc = key.IndexOf("(");
                int length = paraLoc - (spaceLoc + 1) - 1;
                if (!spaceLoc.Equals(-1) && !paraLoc.Equals(-1) && length > 0)
                    gametypeName = key.Substring(spaceLoc + 1, length);
            }
            else if (key.Equals("Any"))
                gametypeName = key;
            else
            {
                int paraLoc = key.IndexOf("(");
                if (!paraLoc.Equals(-1))
                    gametypeName = key.Substring(0, paraLoc - 1);
            }
            if (this.gametypeCollection.ContainsKey(gametypeName))
                return this.gametypeCollection[gametypeName];
            else
                return new List<int>();
        }

        public List<string> GetBasePlaylists()
        {
            List<string> playlists = new List<string>();
            foreach (string game in baseGametypes.Keys)
                playlists.Add(game);
            return playlists;
        }

        public Dictionary<string, List<int>> GetPlayListConversions()
        {
            return this.baseGametypes;
        }
    }
}
